home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World's Largest Collection of Windows Software
/
The World's Largest Collection of Windows Software - Disc 2.iso
/
games
/
_b2
/
winmaze4
/
plot3d.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1994-05-19
|
48KB
|
1,097 lines
#include <owl\owlpch.h>
#include <owl\applicat.h>
#include <owl\framewin.h>
#include <owl\dc.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include "plot3d.h"
#ifndef TRUE
#define TRUE -1
#endif
#ifndef FALSE
#define FALSE 0
#endif
plot3d::plot3d(TFrameWindow *ptr)
{
window_ptr=ptr;
TClientDC *dc=new TClientDC(*window_ptr);
long num_colors_free=1L
<< (long(dc->GetDeviceCaps(PLANES))*long(dc->GetDeviceCaps(BITSPIXEL)));
num_colors_free-=long(dc->GetDeviceCaps(NUMCOLORS));
delete dc;
if (num_colors_free < 16L)
{
use_palette=FALSE;
num_colors=256;
}
else
{
use_palette=TRUE;
if (num_colors_free > 256L)
num_colors=256;
else
num_colors=int(num_colors_free);
}
corner_allocated=FALSE;
plot_prepared=FALSE;
prepare_plot_state='B';
plot_state='B';
int color_num;
for (int color_index=0; color_index < (num_colors-1); color_index++)
{
color_num=int((255L*long(color_index))/long(num_colors-2));
palette_entry[color_index].peRed=(BYTE) color_num;
palette_entry[color_index].peGreen=(BYTE) color_num;
palette_entry[color_index].peBlue=(BYTE) color_num;
palette_entry[color_index].peFlags=(BYTE) PC_NOCOLLAPSE;
}
palette_entry[color_index].peRed=(BYTE) 255;
palette_entry[color_index].peGreen=(BYTE) 0;
palette_entry[color_index].peBlue=(BYTE) 0;
palette_entry[color_index].peFlags=(BYTE) PC_NOCOLLAPSE;
palette=new TPalette(&palette_entry[0],num_colors);
lightest_gray=int((240L*long(num_colors-2))/254L);
darkest_gray=(19*(num_colors-2))/254;
}
plot3d::~plot3d()
{
delete palette;
if (corner_allocated)
{
for (x_division_num=(num_x_divisions-1); x_division_num >= 0;
x_division_num--)
delete[] corner[x_division_num--];
delete[] corner;
}
}
char plot3d::prepare_plot(
double (*f)(double,double),
double x_min,
double x_max,
double y_min,
double y_max,
int (*external_to_plot)(double,double),
int (*red)(double,double),
int x_division_count,
int y_division_count,
double rotation_in_degrees,
double tilt_in_degrees,
double light_x,
double light_y,
double light_z)
// This function returns 'S' if it is successful in preparing the plot for
// generation. It returns 'C' if it should be called again (because more work
// must be done). Otherwise, it returns 'F' indicating a failure. Its
// parameters are as follow:
//
// f -- z=f(x,y), the function to be plotted. Before the plot is
// tilted or rotated, the z-axis runs from the bottom to the top of the
// display, the y-axis runs from the left to the right of the display,
// and the x-axis runs out of the display.
//
// x_min -- the minimum value of x to be plotted.
//
// x_max -- the maximum value of x to be plotted.
//
// y_min -- the minimum value of y to be plotted.
//
// y_max -- the maximum value of y to be plotted.
//
// external_to_plot -- a function that returns TRUE if and only if a
// point should be omitted from the plot.
//
// red -- a function that returns TRUE if and only if a point should
// be flagged for highlighting. A point should be so flagged only if it
// can be seen in the final plot.
//
// x_division_count -- the number of x divisions to be used in
// constructing the plot. At least two must be specified.
//
// y_division_count -- the number of y divisions to be used in
// constructing the plot. At least two must be specified.
//
// rotation_in_degrees -- rotation (degrees) about an axis parallel to
// the z-axis and through the center of the surface.
//
// tilt_in_degrees -- tilt (degrees) about an axis through the center
// of the surface and parallel to a line from the lower left hand corner of
// the display to the lower right hand corner of the display. The plot is
// tilted after it is rotated.
//
// (light_x,light_y,light_z) -- a vector pointing to the light source
// (at infinity). The light source remains fixed while the plot is rotated
// or tilted.
{
char result;
result='C';
switch (prepare_plot_state)
{
case 'B': // begin
plot_prepared=FALSE;
if (corner_allocated)
{
for (x_division_num=(num_x_divisions-1); x_division_num >= 0;
x_division_num--)
delete[] corner[x_division_num--];
delete[] corner;
corner_allocated=FALSE;
}
num_x_divisions=x_division_count;
num_y_divisions=y_division_count;
corner_allocated
=((corner=new corner_rec_ptr [num_x_divisions]) != NULL);
for (x_division_num=0;
((corner_allocated) && (x_division_num < num_x_divisions));
x_division_num++)
if (corner_allocated=
((corner [x_division_num]=new corner_rec [num_y_divisions])
!= NULL))
for (y_division_num=0; y_division_num < num_y_divisions;
y_division_num++)
{
corner[x_division_num][y_division_num].base_z
=(unsigned char) '\0';
corner[x_division_num][y_division_num].color
=(unsigned char) '\0';
corner[x_division_num][y_division_num].x=(float) 0.0;
corner[x_division_num][y_division_num].y=(float) 0.0;
corner[x_division_num][y_division_num].z=(float) 0.0;
corner[x_division_num][y_division_num].x_division_index=0;
corner[x_division_num][y_division_num].y_division_index=0;
};
if (corner_allocated)
{
rotation=rotation_in_degrees;
tilt=tilt_in_degrees;
light.x=light_x;
light.y=light_y;
light.z=light_z;
prepare_plot_state='E';
TClientDC *dc=new TClientDC(*window_ptr);
dc->PatBlt(window_ptr->GetClientRect(),WHITENESS);
dc->TextOut(0,0,"Evaluating...");
delete dc;
x_division_num=0;
y_division_num=0;
}
else
{
x_division_num--;
while (x_division_num >= 0)
delete[] corner[x_division_num--];
delete[] corner;
prepare_plot_state='F';
result='F';
}
break;
case 'E': // evaluate and transform
evaluate_and_transform(f,x_min,x_max,y_min,y_max,
num_x_divisions,num_y_divisions,rotation,tilt,
external_to_plot,red);
// Compute the vertices, etc. of the quadrilaterals composing the
// plot.
if (x_division_num >= num_x_divisions)
{
prepare_plot_state='H';
TClientDC *dc=new TClientDC(*window_ptr);
dc->PatBlt(window_ptr->GetClientRect(),WHITENESS);
dc->TextOut(0,0,"Shading...");
delete dc;
x_division_num=num_x_divisions-1;
y_division_num=num_y_divisions-1;
}
break;
case 'H': // shade
shade();
// Compute the shade of gray for each quadrilateral composing the
// plot.
if (x_division_num < 0)
{
if (((y_corner_max-y_corner_min) > (z_corner_max-z_corner_min))
|| (z_corner_max != z_corner_min))
{
if ((y_corner_max-y_corner_min)
> (z_corner_max-z_corner_min))
x_eye=1.1*(y_corner_max-y_corner_min)+x_corner_max;
else
x_eye=1.1*(z_corner_max-z_corner_min)+x_corner_max;
prepare_plot_state='A';
TClientDC *dc=new TClientDC(*window_ptr);
dc->PatBlt(window_ptr->GetClientRect(),WHITENESS);
dc->TextOut(0,0,"Adjusting perspective...");
delete dc;
x_division_num=0;
y_division_num=0;
}
else
{
stacked_bound_head=new sort_stack_rec;
stacked_bound_head->bound.lower_x=0;
stacked_bound_head->bound.lower_y=0;
stacked_bound_head->bound.upper_x=(num_x_divisions-1);
stacked_bound_head->bound.upper_y=(num_y_divisions-1);
stacked_bound_head->previous=NULL;
prepare_plot_state='S';
TClientDC *dc=new TClientDC(*window_ptr);
dc->PatBlt(window_ptr->GetClientRect(),WHITENESS);
dc->TextOut(0,0,"Sorting...");
delete dc;
}
}
break;
case 'A': // adjust perspective
adjust_perspective();
// Force parallel lines running away from the viewer to converge
// at the horizon.
if (x_division_num >= num_x_divisions)
{
stacked_bound_head=new sort_stack_rec;
stacked_bound_head->bound.lower_x=0;
stacked_bound_head->bound.lower_y=0;
stacked_bound_head->bound.upper_x=(num_x_divisions-1);
stacked_bound_head->bound.upper_y=(num_y_divisions-1);
stacked_bound_head->previous=NULL;
prepare_plot_state='S';
TClientDC *dc=new TClientDC(*window_ptr);
dc->PatBlt(window_ptr->GetClientRect(),WHITENESS);
dc->TextOut(0,0,"Sorting...");
delete dc;
}
break;
case 'S': // sort back to front
sort_back_to_front();
if (stacked_bound_head == NULL)
{
prepare_plot_state='D';
TClientDC *dc=new TClientDC(*window_ptr);
dc->PatBlt(window_ptr->GetClientRect(),WHITENESS);
delete dc;
}
break;
case 'F': // failed
result='F';
break;
default: // done
plot_prepared=TRUE;
result='S';
break;
}
return result;
}
void plot3d::evaluate_and_transform(
double (*f)(double,double),
double x_min,
double x_max,
double y_min,
double y_max,
int num_x_divisions,
int num_y_divisions,
double rotation,
double tilt,
int (*external_to_plot)(double,double),
int (*red)(double,double))
// Compute the vertices, etc. for each quadrilateral composing the plot.
{
double tem_x;
double tem_y;
double tem_z;
double x_rotated;
double z;
if ((x_division_num == 0) && (y_division_num == 0))
{
double degrees_per_radian=45.0/atan(1.0);
radians=tilt/degrees_per_radian;
cos_tilt=cos(radians);
sin_tilt=sin(radians);
radians=rotation/degrees_per_radian;
cos_rotation=cos(radians);
sin_rotation=sin(radians);
z=f(x_min,y_min);
x_rotated=x_min*cos_rotation+y_min*sin_rotation;
y_corner_min=-x_min*sin_rotation+y_min*cos_rotation;
z_corner_min=-x_rotated*sin_tilt+z*cos_tilt;
y_corner_max=y_corner_min;
z_corner_max=z_corner_min;
x_corner_max=x_rotated*cos_tilt+z*sin_tilt;
x_delta=(double) (num_x_divisions-1);
x_delta=(x_max-x_min)/x_delta;
y_delta=(double) (num_y_divisions-1);
y_delta=(y_max-y_min)/y_delta;
x=x_min;
y=y_min;
}
int finished=FALSE;
DWORD start_time=GetTickCount();
DWORD current_time;
while ((! finished) && (x_division_num < num_x_divisions))
{
z=f(x,y);
if (external_to_plot(x,y))
corner[x_division_num][y_division_num].base_z=(unsigned char) 3;
else
if (red(x,y))
corner[x_division_num][y_division_num].base_z=(unsigned char) 2;
else
corner[x_division_num][y_division_num].base_z=(unsigned char) 1;
corner[x_division_num][y_division_num].x_division_index
=x_division_num;
corner[x_division_num][y_division_num].y_division_index
=y_division_num;
x_rotated=x*cos_rotation+y*sin_rotation;
tem_y=(-x*sin_rotation+y*cos_rotation);
corner[x_division_num][y_division_num].y=(float) tem_y;
tem_x=(x_rotated*cos_tilt+z*sin_tilt);
corner[x_division_num][y_division_num].x=(float) tem_x;
tem_z=(-x_rotated*sin_tilt+z*cos_tilt);
corner[x_division_num][y_division_num].z=(float) tem_z;
if (tem_x > x_corner_max)
x_corner_max=tem_x;
if (tem_y < y_corner_min)
y_corner_min=tem_y;
if (tem_y > y_corner_max)
y_corner_max=tem_y;
if (tem_z < z_corner_min)
z_corner_min=tem_z;
if (tem_z > z_corner_max)
z_corner_max=tem_z;
y+=y_delta;
y_division_num++;
if (y_division_num >= num_y_divisions)
{
y_division_num=0;
y=y_min;
x+=x_delta;
x_division_num++;
}
current_time=GetTickCount();
finished=((current_time < start_time)
|| ((current_time-start_time) > 100));
}
if (x_division_num >= num_x_divisions)
{
double magnitude=light.x*light.x+light.y*light.y+light.z*light.z;
magnitude=sqrt(magnitude);
light.x=light.x/magnitude;
light.y=light.y/magnitude;
light.z=light.z/magnitude;
}
return;
}
void plot3d::shade()
// Compute the shade of gray for each quadrilateral composing the plot.
{
int color_num;
double magnitude;
vertex_rec normal;
vertex_rec vertex [4];
if ((x_division_num == (num_x_divisions-1))
&& (y_division_num == (num_y_divisions-1)))
{
color_min=(unsigned char) (num_colors-1);
color_max=(unsigned char) '\0';
}
int finished=FALSE;
DWORD start_time=GetTickCount();
DWORD current_time;
while ((! finished) && (x_division_num >= 0))
{
vertex[0].x=(double) (corner[x_division_num][y_division_num].x);
vertex[0].y=(double) (corner[x_division_num][y_division_num].y);
vertex[0].z=(double) (corner[x_division_num][y_division_num].z);
if (x_division_num < (num_x_divisions-1))
if (y_division_num < (num_y_divisions-1))
{
x_division_num++;
vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
y_division_num++;
vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
x_division_num--;
vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
y_division_num--;
}
else
{
y_division_num--;
vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
x_division_num++;
vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
y_division_num++;
vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
x_division_num--;
}
else
if (y_division_num < (num_y_divisions-1))
{
y_division_num++;
vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
x_division_num--;
vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
y_division_num--;
vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
x_division_num++;
}
else
{
x_division_num--;
vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
y_division_num--;
vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
x_division_num++;
vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
y_division_num++;
}
// Compute the normal to a quadrilateral by averaging the
// normals to each vertex of the quadrilateral.
normal.x
=(vertex[1].y-vertex[0].y)*(vertex[3].z-vertex[0].z)
-(vertex[3].y-vertex[0].y)*(vertex[1].z-vertex[0].z)
+(vertex[2].y-vertex[1].y)*(vertex[0].z-vertex[1].z)
-(vertex[0].y-vertex[1].y)*(vertex[2].z-vertex[1].z)
+(vertex[3].y-vertex[2].y)*(vertex[1].z-vertex[2].z)
-(vertex[1].y-vertex[2].y)*(vertex[3].z-vertex[2].z)
+(vertex[0].y-vertex[3].y)*(vertex[2].z-vertex[3].z)
-(vertex[2].y-vertex[3].y)*(vertex[0].z-vertex[3].z);
normal.y
=(vertex[3].x-vertex[0].x)*(vertex[1].z-vertex[0].z)
-(vertex[1].x-vertex[0].x)*(vertex[3].z-vertex[0].z)
+(vertex[0].x-vertex[1].x)*(vertex[2].z-vertex[1].z)
-(vertex[2].x-vertex[1].x)*(vertex[0].z-vertex[1].z)
+(vertex[1].x-vertex[2].x)*(vertex[3].z-vertex[2].z)
-(vertex[3].x-vertex[2].x)*(vertex[1].z-vertex[2].z)
+(vertex[2].x-vertex[3].x)*(vertex[0].z-vertex[3].z)
-(vertex[0].x-vertex[3].x)*(vertex[2].z-vertex[3].z);
normal.z
=(vertex[1].x-vertex[0].x)*(vertex[3].y-vertex[0].y)
-(vertex[3].x-vertex[0].x)*(vertex[1].y-vertex[0].y)
+(vertex[2].x-vertex[1].x)*(vertex[0].y-vertex[1].y)
-(vertex[0].x-vertex[1].x)*(vertex[2].y-vertex[1].y)
+(vertex[3].x-vertex[2].x)*(vertex[1].y-vertex[2].y)
-(vertex[1].x-vertex[2].x)*(vertex[3].y-vertex[2].y)
+(vertex[0].x-vertex[3].x)*(vertex[2].y-vertex[3].y)
-(vertex[2].x-vertex[3].x)*(vertex[0].y-vertex[3].y);
magnitude
=sqrt(normal.x*normal.x+normal.y*normal.y+normal.z*normal.z);
if (magnitude == 0.0)
{
color_min=(unsigned char) '\0';
corner[x_division_num][y_division_num].color=(unsigned char) '\0';
}
else
{
color_num=int((double(num_colors)/2.0)
*(1.0+(light.x*normal.x+light.y*normal.y
+light.z*normal.z)/magnitude)); // shadows not absolute
if (color_num >= num_colors)
color_num=num_colors-1;
corner[x_division_num][y_division_num].color
=(unsigned char) color_num;
if ((corner[x_division_num][y_division_num].color) < color_min)
color_min=(corner[x_division_num][y_division_num].color);
if ((corner[x_division_num][y_division_num].color) > color_max)
color_max=(corner[x_division_num][y_division_num].color);
}
y_division_num--;
if (y_division_num < 0)
{
y_division_num=num_y_divisions-1;
x_division_num--;
}
current_time=GetTickCount();
finished=((current_time < start_time)
|| ((current_time-start_time) > 100));
}
return;
}
void plot3d::adjust_perspective()
// Make parallel lines running away from the viewer appear to converge at the
// horizon.
{
double tem;
vertex_rec vertex [4];
if ((x_division_num == 0) && (y_division_num == 0))
{
y_center=(y_corner_max+y_corner_min)/2.0;
z_center=(z_corner_max+z_corner_min)/2.0;
}
int finished=FALSE;
DWORD start_time=GetTickCount();
DWORD current_time;
while ((! finished) && (x_division_num < num_x_divisions))
{
vertex[0].x=(double) (corner[x_division_num][y_division_num].x);
vertex[0].y=(double) (corner[x_division_num][y_division_num].y);
vertex[0].z=(double) (corner[x_division_num][y_division_num].z);
if (x_division_num < (num_x_divisions-1))
if (y_division_num < (num_y_divisions-1))
{
x_division_num++;
vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
y_division_num++;
vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
x_division_num--;
vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
y_division_num--;
}
else
{
y_division_num--;
vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
x_division_num++;
vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
y_division_num++;
vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
x_division_num--;
}
else
if (y_division_num < (num_y_divisions-1))
{
y_division_num++;
vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
x_division_num--;
vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
y_division_num--;
vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
x_division_num++;
}
else
{
x_division_num--;
vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
y_division_num--;
vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
x_division_num++;
vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
y_division_num++;
}
tem=y_center
+(vertex[0].y-y_center)*(x_eye-x_corner_max)
/(x_eye-vertex[0].x);
corner[x_division_num][y_division_num].y=(float) tem;
tem=z_center
+(vertex[0].z-z_center)*(x_eye-x_corner_max)
/(x_eye-vertex[0].x);
corner[x_division_num][y_division_num].z=(float) tem;
tem=(vertex[0].x+vertex[1].x+vertex[2].x+vertex[3].x)/4.0;
corner[x_division_num][y_division_num].x=(float) tem;
y_division_num++;
if (y_division_num >= num_y_divisions)
{
y_division_num=0;
x_division_num++;
}
current_time=GetTickCount();
finished=((current_time < start_time)
|| ((current_time-start_time) > 100));
}
return;
}
void plot3d::rearrange(
int lower_bound_x,
int lower_bound_y,
int upper_bound_x,
int upper_bound_y,
int *j_x,
int *j_y)
{
int down_x;
int down_y;
int finished;
int up_x;
int up_y;
float x1;
int x_division_index1;
int y_division_index1;
x1=corner[lower_bound_x][lower_bound_y].x;
x_division_index1=corner[lower_bound_x][lower_bound_y].x_division_index;
y_division_index1=corner[lower_bound_x][lower_bound_y].y_division_index;
*j_x=lower_bound_x;
*j_y=lower_bound_y;
up_x=upper_bound_x;
up_y=upper_bound_y;
down_x=lower_bound_x;
down_y=lower_bound_y;
do
{
finished=FALSE;
while (! finished)
{
if ((up_x < down_x)
|| ((up_x == down_x) && (up_y <= down_y)))
finished=TRUE;
else
if (corner[up_x][up_y].x < x1)
finished=TRUE;
else
{
if (--up_y < 0)
{
up_y=num_y_divisions-1;
up_x--;
}
}
}
*j_x=up_x;
*j_y=up_y;
if ((up_x != down_x) || (up_y != down_y))
{
corner[down_x][down_y].x=corner[up_x][up_y].x;
corner[down_x][down_y].x_division_index
=corner[up_x][up_y].x_division_index;
corner[down_x][down_y].y_division_index
=corner[up_x][up_y].y_division_index;
finished=FALSE;
while (! finished)
{
if ((down_x > up_x)
|| ((down_x == up_x) && (down_y >= up_y)))
finished=TRUE;
else
if (corner[down_x][down_y].x > x1)
finished=TRUE;
else
{
if (++down_y >= num_y_divisions)
{
down_y=0;
down_x++;
}
}
}
*j_x=down_x;
*j_y=down_y;
if ((down_x != up_x) || (down_y != up_y))
{
corner[up_x][up_y].x=corner[down_x][down_y].x;
corner[up_x][up_y].x_division_index
=corner[down_x][down_y].x_division_index;
corner[up_x][up_y].y_division_index
=corner[down_x][down_y].y_division_index;
}
}
}
while ((down_x != up_x) || (down_y != up_y));
corner[*j_x][*j_y].x=x1;
corner[*j_x][*j_y].x_division_index=x_division_index1;
corner[*j_x][*j_y].y_division_index=y_division_index1;
return;
}
void plot3d::sort_back_to_front()
// The painter's algorithm is used; items farther from the viewer are drawn
// earlier.
{
int i_x;
int i_y;
int j_x;
int j_y;
sort_bound_rec stacked_bound;
sort_stack_rec *stacked_bound_ptr;
int finished=FALSE;
DWORD start_time=GetTickCount();
DWORD current_time;
while ((! finished) && (stacked_bound_head != NULL))
{
stacked_bound.lower_x=stacked_bound_head->bound.lower_x;
stacked_bound.lower_y=stacked_bound_head->bound.lower_y;
stacked_bound.upper_x=stacked_bound_head->bound.upper_x;
stacked_bound.upper_y=stacked_bound_head->bound.upper_y;
stacked_bound_ptr=stacked_bound_head;
stacked_bound_head=stacked_bound_head->previous;
delete stacked_bound_ptr;
while ((stacked_bound.upper_x > stacked_bound.lower_x)
|| ((stacked_bound.upper_x == stacked_bound.lower_x)
&& (stacked_bound.upper_y > stacked_bound.lower_y)))
{
rearrange(stacked_bound.lower_x,stacked_bound.lower_y,
stacked_bound.upper_x,stacked_bound.upper_y,&j_x,&j_y);
if (long(num_y_divisions)*long(j_x-stacked_bound.lower_x)
+(j_y-stacked_bound.lower_y)
> long(num_y_divisions)*long(stacked_bound.upper_x-j_x)
+(stacked_bound.upper_y-j_y))
{
i_x=stacked_bound.upper_x;
i_y=stacked_bound.upper_y;
stacked_bound.upper_y=j_y-1;
stacked_bound.upper_x=j_x;
if (stacked_bound.upper_y < 0)
{
stacked_bound.upper_y=num_y_divisions-1;
(stacked_bound.upper_x)--;
}
stacked_bound_ptr=new sort_stack_rec;
stacked_bound_ptr->bound.lower_x=stacked_bound.lower_x;
stacked_bound_ptr->bound.lower_y=stacked_bound.lower_y;
stacked_bound_ptr->bound.upper_x=stacked_bound.upper_x;
stacked_bound_ptr->bound.upper_y=stacked_bound.upper_y;
stacked_bound_ptr->previous=stacked_bound_head;
stacked_bound_head=stacked_bound_ptr;
stacked_bound.lower_y=j_y+1;
stacked_bound.lower_x=j_x;
if (stacked_bound.lower_y >= num_y_divisions)
{
stacked_bound.lower_y=0;
(stacked_bound.lower_x)++;
}
stacked_bound.upper_x=i_x;
stacked_bound.upper_y=i_y;
}
else
{
i_x=stacked_bound.lower_x;
i_y=stacked_bound.lower_y;
stacked_bound.lower_y=j_y+1;
stacked_bound.lower_x=j_x;
if (stacked_bound.lower_y >= num_y_divisions)
{
stacked_bound.lower_y=0;
(stacked_bound.lower_x)++;
}
stacked_bound_ptr=new sort_stack_rec;
stacked_bound_ptr->bound.lower_x=stacked_bound.lower_x;
stacked_bound_ptr->bound.lower_y=stacked_bound.lower_y;
stacked_bound_ptr->bound.upper_x=stacked_bound.upper_x;
stacked_bound_ptr->bound.upper_y=stacked_bound.upper_y;
stacked_bound_ptr->previous=stacked_bound_head;
stacked_bound_head=stacked_bound_ptr;
stacked_bound.lower_x=i_x;
stacked_bound.lower_y=i_y;
stacked_bound.upper_y=j_y-1;
stacked_bound.upper_x=j_x;
if (stacked_bound.upper_y < 0)
{
stacked_bound.upper_y=num_y_divisions-1;
(stacked_bound.upper_x)--;
}
}
}
current_time=GetTickCount();
finished=((current_time < start_time)
|| ((current_time-start_time) > 100));
}
return;
}
char plot3d::plot(
TRect ®ion_to_paint,
int show_red,
int only_plot_red,
double bias)
// This function returns 'S' if it is successful in generating the 3D plot.
// It returns 'C' if it should be called again (because more work must be done
// on the plot). Otherwise, it returns 'F' indicating a failure. Its
// parameters are as follow:
//
// region_to_paint -- only points in this rectangle will be plotted.
//
// show_red -- highlight quadrilaterals having each vertex flagged
// to be highlighted.
//
// only_plot_red -- only plot the quadrilaterals having each vertex
// flagged to be highlighted.
//
// bias -- a positive number used to adjust the contrast.
//
// "prepare_plot" must be called before "plot", after which "plot" may be called
// as many times as desired.
{
TPoint box [4];
int box_num;
int color_num;
DWORD current_time;
int finished;
double fraction;
int outside_maze;
int red_showing;
char result;
DWORD start_time;
vertex_rec vertex [4];
int x_division_index;
int y_division_index;
double y_out_max;
if (plot_prepared)
{
result='C';
TClientDC *dc=new TClientDC(*window_ptr);
TRect ClipBox;
if (dc->GetClipBox(ClipBox) != NULLREGION)
switch (plot_state)
{
case 'B': // begin
aspect_ratio
=(double(dc->GetDeviceCaps(VERTSIZE))
/double(dc->GetDeviceCaps(HORZSIZE)))
/(double(dc->GetDeviceCaps(VERTRES))
/double(dc->GetDeviceCaps(HORZRES)));
y_out_max=double(window_ptr->GetClientRect().Width()-1);
z_out_max=double(window_ptr->GetClientRect().Height()-1);
if (aspect_ratio*z_out_max*(y_corner_max-y_corner_min)
> y_out_max*(z_corner_max-z_corner_min))
{
pixels_per_unit
=y_out_max/(aspect_ratio*(y_corner_max-y_corner_min));
y_offset=0.0;
z_offset
=-(z_out_max-pixels_per_unit*(z_corner_max-z_corner_min))
/2.0;
}
else
if (aspect_ratio*z_out_max*(y_corner_max-y_corner_min)
< y_out_max*(z_corner_max-z_corner_min))
{
pixels_per_unit=z_out_max/(z_corner_max-z_corner_min);
y_offset=(y_out_max
-aspect_ratio*pixels_per_unit
*(y_corner_max-y_corner_min))/2.0;
z_offset=0.0;
}
else
{
pixels_per_unit=1.0;
y_offset=y_out_max/2.0;
z_offset=-z_out_max/2.0;
}
x_division_num=y_division_num=0;
plot_state='P';
break;
case 'P': // plot
finished=FALSE;
start_time=GetTickCount();
while ((! finished) && (x_division_num < num_x_divisions))
{
x_division_index
=corner[x_division_num][y_division_num].x_division_index;
if (x_division_index < (num_x_divisions-1))
{
y_division_index=corner[x_division_num][
y_division_num].y_division_index;
if (y_division_index < (num_y_divisions-1))
{
color_num=int(corner[x_division_index][
y_division_index].color);
// Adjust contrast.
fraction=((double) (color_num-int(color_min)))
/((double) (color_max-color_min));
if (fraction > 0.0)
{
fraction=exp(bias*log(fraction));
color_num=(int)
(((double) (lightest_gray-darkest_gray))
*fraction
+((double) darkest_gray));
}
else
color_num=darkest_gray;
vertex[0].y=(double)
(corner[x_division_index][y_division_index].y);
vertex[0].z=(double)
(corner[x_division_index][y_division_index].z);
red_showing=(corner[x_division_index][
y_division_index].base_z == (unsigned char) 2);
outside_maze=(corner[x_division_index][
y_division_index].base_z == (unsigned char) 3);
x_division_index++;
vertex[1].y=(double)
(corner[x_division_index][y_division_index].y);
vertex[1].z=(double)
(corner[x_division_index][y_division_index].z);
if (red_showing)
red_showing=(corner[x_division_index][
y_division_index].base_z == (unsigned char) 2);
if (outside_maze)
outside_maze=(corner[x_division_index][
y_division_index].base_z == (unsigned char) 3);
y_division_index++;
vertex[2].y=(double)
(corner[x_division_index][y_division_index].y);
vertex[2].z=(double)
(corner[x_division_index][y_division_index].z);
if (red_showing)
red_showing=(corner[x_division_index][
y_division_index].base_z == (unsigned char) 2);
if (outside_maze)
outside_maze=(corner[x_division_index][
y_division_index].base_z == (unsigned char) 3);
x_division_index--;
vertex[3].y=(double)
(corner[x_division_index][y_division_index].y);
vertex[3].z=(double)
(corner[x_division_index][y_division_index].z);
if (red_showing)
red_showing=(corner[x_division_index][
y_division_index].base_z == (unsigned char) 2);
if (outside_maze)
outside_maze=(corner[x_division_index][
y_division_index].base_z == (unsigned char) 3);
if (((! only_plot_red) || (red_showing))
&& (! outside_maze))
// Plot each point in a quadrilateral.
{
for (box_num=0; box_num < 4; box_num++)
{
box[box_num].x=(int) (y_offset
+pixels_per_unit*aspect_ratio
*(vertex[box_num].y-y_corner_min));
box[box_num].y
=(int) (z_offset+z_out_max
-pixels_per_unit
*(vertex[box_num].z-z_corner_min));
}
dc->SelectClipRgn(region_to_paint);
if (use_palette)
{
dc->SelectObject(*palette);
dc->RealizePalette();
if ((show_red) && (red_showing))
{
TColor palColor(num_colors-1);
TBrush brush(palColor);
dc->SelectObject(brush);
TPen pen(palColor,1,PS_NULL);
dc->SelectObject(pen);
dc->Polygon(&box[0],4);
dc->RestorePen();
dc->RestoreBrush();
}
else
{
TColor palColor(color_num);
TBrush brush(palColor);
dc->SelectObject(brush);
TPen pen(palColor,1,PS_NULL);
dc->SelectObject(pen);
dc->Polygon(&box[0],4);
dc->RestorePen();
dc->RestoreBrush();
}
dc->RestorePalette();
}
else
{
if ((show_red) && (red_showing))
{
TBrush brush(RGB(255,0,0));
dc->SelectObject(brush);
TPen pen(RGB(255,0,0),1,PS_NULL);
dc->SelectObject(pen);
dc->Polygon(&box[0],4);
dc->RestorePen();
dc->RestoreBrush();
}
else
{
TBrush brush(RGB(color_num,color_num,
color_num));
dc->SelectObject(brush);
TPen pen(RGB(color_num,color_num,
color_num),1,PS_NULL);
dc->SelectObject(pen);
dc->Polygon(&box[0],4);
dc->RestorePen();
dc->RestoreBrush();
}
}
}
}
}
if (++y_division_num >= num_y_divisions)
{
y_division_num=0;
x_division_num++;
}
current_time=GetTickCount();
finished=((current_time < start_time)
|| ((current_time-start_time) > 100));
}
if (x_division_num >= num_x_divisions)
plot_state='S';
break;
case 'F': // failed
result='F';
break;
default: // done
result='S';
break;
}
delete dc;
}
else
{
result='F'; // attempt to plot before prepared
window_ptr->MessageBox("Attempt to plot before prepared!",
window_ptr->GetApplication()->GetName(),
MB_OK | MB_ICONEXCLAMATION);
}
return result;
}
void plot3d::restart_plot()
{
if (plot_prepared)
plot_state='B';
}